from decimal import Decimal

from fastapi import APIRouter, HTTPException
from fastapi.params import Depends, Query
from tortoise.contrib.pydantic import pydantic_model_creator
from tortoise.transactions import in_transaction
from datetime import datetime
import uuid

from MyOAuth import my_oauth2_scheme
from db.models.move import MoveOrder, MoveItem
from db.models.product import Product
from db.models.warehouse import Warehouse
from db.models.store import Store
from db.models.user import User
from ApiResponse import ApiResponse, PageResult
from pydantic import BaseModel, Field
from typing import List, Optional

# 创建路由
move_router = APIRouter()


class MoveItemRequest(BaseModel):
    """调拨订单商品项请求模型"""
    pid: int = Field(example=1, description='商品ID')
    unit: str = Field(example='箱', description='计量单位：箱/瓶')
    number: float = Field(example=10, gt=0, description='商品数量')


class CreateMoveRequest(BaseModel):
    """创建调拨订单请求模型"""
    whoutid: int = Field(example=3, description='调出仓库ID')
    whinid: int = Field(example=3, description='调入仓库ID')
    owner: int = Field(example=1, default=None, description='经办人ID')
    list: List[MoveItemRequest] = Field(
        example=[
            {"pid": 1, "unit": "瓶", "number": 10},
            {"pid": 2, "unit": "瓶", "number": 20}
        ],
        min_items=1,
        description='至少包含一个商品项'
    )


@move_router.post("/create", summary="创建调拨订单")
async def create_move_order(request: CreateMoveRequest, token: dict = Depends(my_oauth2_scheme)):
    """
    创建调拨订单接口
    
    参数:
    - whoutid: 调出仓库ID
    - whinid: 调入仓库ID  
    - owner: 经办人ID
    - list: 商品列表，包含商品ID、单位和数量
    """
    try:
        async with in_transaction():

            # 生成调拨单号
            move_id = f"MO{datetime.now().strftime('%Y%m%d')}{uuid.uuid4().hex[:4]}"

            # 检查调出仓库和调入仓库是否相同
            if request.whoutid == request.whinid:
                return ApiResponse.error(400, "调出仓库和调入仓库不能相同")

            # 检查调出仓库和调入仓库是否存在
            whout = await Warehouse.get_or_none(whid=request.whoutid, del_flag__not="2")
            whin = await Warehouse.get_or_none(whid=request.whinid, del_flag__not="2")

            if not whout:
                return ApiResponse.error(400, f"调出仓库ID {request.whoutid} 不存在")
            if not whin:
                return ApiResponse.error(400, f"调入仓库ID {request.whinid} 不存在")

            total_amount = 0.0
            order_items = []

            # 处理每个商品项
            for index, item in enumerate(request.list):
                # 检查商品是否存在
                product = await Product.get_or_none(pid=item.pid, del_flag__not="2")
                if not product:
                    return ApiResponse.error(400, f"商品ID {item.pid} 不存在")

                # 检查调出仓库库存是否足够
                store_out = await Store.get_or_none(
                    pid=item.pid,
                    whid=request.whoutid,
                    del_flag__not="2"
                )

                if not store_out:
                    return ApiResponse.error(400, f"商品 {product.pname} 在调出仓库无库存")

                # 根据单位类型转换数量
                actual_number = item.number
                if item.unit == product.bigunit and product.formulanum:
                    # 如果是大单位，需要乘以换算系数
                    actual_number = item.number * product.formulanum
                elif item.unit == product.smallunit:
                    # 如果是小单位，直接使用原数量
                    actual_number = item.number
                else:
                    # 如果单位不匹配，返回错误
                    return ApiResponse.error(400, f"商品 {product.pname} 的单位 '{item.unit}' 与商品定义的单位不匹配（大单位: {product.bigunit}, 小单位: {product.smallunit}）")

                # 检查可用数量是否足够
                if not hasattr(store_out, 'availablenum') or store_out.availablenum is None:
                    return ApiResponse.error(400, f"商品 {product.pname} 可用数量字段不存在或为空")

                # 转换Decimal为float进行比较
                available_num = float(store_out.availablenum)
                if available_num < actual_number:
                    return ApiResponse.error(400, f"商品 {product.pname} 在调出仓库可用数量不足，当前可用数量: {available_num}")

                # 获取或创建调入仓库库存记录
                store_in = await Store.get_or_none(
                    pid=item.pid,
                    whid=request.whinid,
                    del_flag__not="2"
                )

                # 根据单位类型转换数量
                actual_number = item.number
                if item.unit == product.bigunit and product.formulanum:
                    # 如果是大单位，需要乘以换算系数
                    actual_number = item.number * product.formulanum
                elif item.unit == product.smallunit:
                    # 如果是小单位，直接使用原数量
                    actual_number = item.number

                if not store_in:
                    # 如果调入仓库没有该商品库存，创建新的库存记录并保存
                    store_in = Store(
                        pid=item.pid,
                        pname=product.pname,
                        unit=item.unit,
                        num=Decimal(str(actual_number)),  # 使用转换后的数量
                        availablenum=Decimal(str(actual_number)),  # 可用数量也设置为转换后的数量
                        whid=request.whinid,
                        create_by=str(token["id"]),
                        create_time=datetime.now(),
                        update_by=str(token["id"]),
                        update_time=datetime.now()
                    )
                    await store_in.save()
                else:
                    # 如果已有库存记录，在后面统一更新
                    store_in.num += Decimal(str(actual_number))
                    store_in.availablenum += Decimal(str(actual_number))
                    store_in.update_by = str(token["id"])
                    store_in.update_time = datetime.now()
                    await store_in.save()

                # 计算金额（这里需要根据实际业务逻辑计算单价）
                # unit_price = product.smallprice if item.unit == product.smallunit else product.bigprice
                # item_amount = unit_price * item.number if unit_price else 0
                # total_amount += item_amount

                # 创建调拨商品项
                move_item = MoveItem(
                    moveid=move_id,
                    orderid=index + 1,
                    pid=item.pid,
                    pname=product.pname,
                    unit=item.unit,
                    # unitprice=unit_price,
                    number=item.number,
                    # orderamount=item_amount,
                    # whnumber=0,  # 初始出库数量为0
                    # whamount=0,  # 初始出库金额为0
                    whid=request.whoutid,
                    whname=whout.whname,
                    create_by=str(token["id"]),
                    create_time=datetime.now(),
                    update_by=str(token["id"]),
                    update_time=datetime.now()
                )
                order_items.append(move_item)

            # 确定owner：如果request.owner为空，则使用当前登录用户ID
            owner_id = request.owner if request.owner else int(token["id"])

            # 创建调拨订单
            move_order = MoveOrder(
                moveid=move_id,
                owner=owner_id,
                whoutid=request.whoutid,
                whinid=request.whinid,
                # orderamount=total_amount,
                whamount=0,  # 初始入库金额为0
                yjamount=0,  # 初始已结款为0
                # wjamount=total_amount,  # 初始未结款为总金额
                statu="待审核",  # 初始状态
                shtime=datetime.now(),
                create_by=str(token["id"]),
                create_time=datetime.now(),
                update_by=str(token["id"]),
                update_time=datetime.now()
            )

            # 保存订单和商品项
            await move_order.save()
            for item in order_items:
                await item.save()

            # 更新调出仓库库存：减去调拨数量
            for index, item in enumerate(request.list):
                # 获取商品信息
                product = await Product.get_or_none(pid=item.pid, del_flag__not="2")
                if not product:
                    continue

                # 获取调出仓库库存记录
                store_out = await Store.get_or_none(
                    pid=item.pid,
                    whid=request.whoutid,
                    del_flag__not="2"
                )

                if store_out:
                    # 根据单位类型转换数量
                    actual_number = item.number
                    if item.unit == product.bigunit and product.formulanum:
                        # 如果是大单位，需要乘以换算系数
                        actual_number = item.number * product.formulanum
                    elif item.unit == product.smallunit:
                        # 如果是小单位，直接使用原数量
                        actual_number = item.number

                    # 调出仓库减去可用数量（需要将float转换为Decimal）
                    if hasattr(store_out, 'availablenum') and store_out.availablenum is not None:
                        store_out.availablenum -= Decimal(str(actual_number))
                        store_out.update_by = str(token["id"])
                        store_out.update_time = datetime.now()
                        await store_out.save()

            return ApiResponse.ok(msg="调拨订单创建成功", data={"moveid": move_id})
    except Exception as e:
        raise ApiResponse.error(500, f"创建调拨订单失败: {str(e)}")


# 创建Pydantic模型
MoveItem_Pydantic = pydantic_model_creator(MoveItem, name="MoveItemResponse")
MoveOrder_Pydantic = pydantic_model_creator(MoveOrder, name="MoveOrderResponse")


@move_router.get('/list', summary="查询当前用户的调拨订单")
async def get_moves_by_current_user(
        page: int = 1,
        limit: int = 10,
        jwt: dict = Depends(my_oauth2_scheme)
) -> ApiResponse[PageResult[dict]]:
    """
    查询当前用户的调拨订单接口
    
    参数:
    - page: 页码，默认为1
    - limit: 每页数量，默认为10
    """
    # 从JWT token中获取当前用户ID
    user_id = jwt["id"]

    # 计算分页偏移量
    offset = (page - 1) * limit

    # 查询该用户的所有调拨订单
    moves = await MoveOrder.filter(
        owner=user_id,
        del_flag__not="2"
    ).order_by("-create_time").offset(offset).limit(limit)

    # 查询总数量
    total_count = await MoveOrder.filter(
        owner=user_id,
        del_flag__not="2"
    ).count()

    # 获取仓库名称信息并构建结果列表
    moves_with_details = []
    for move in moves:
        # 获取经办人名称
        owner_name = None
        if move.owner:
            owner_user = await User.filter(user_id=move.owner, del_flag__not="2").first()
            if owner_user:
                owner_name = owner_user.nick_name

        # 获取调出仓库名称
        whout = await Warehouse.get_or_none(whid=move.whoutid, del_flag__not="2")
        whout_name = whout.whname if whout else "未知仓库"

        # 获取调入仓库名称
        whin = await Warehouse.get_or_none(whid=move.whinid, del_flag__not="2")
        whin_name = whin.whname if whin else "未知仓库"

        # 格式化日期字段
        shtime_str = move.shtime.strftime("%Y-%m-%d %H:%M:%S") if move.shtime else None
        create_time_str = move.create_time.strftime("%Y-%m-%d %H:%M:%S") if move.create_time else None
        update_time_str = move.update_time.strftime("%Y-%m-%d %H:%M:%S") if move.update_time else None

        # 构建结果字典
        move_dict = {
            "moveid": move.moveid,
            "owner": move.owner,
            "ownername": owner_name,
            "whoutid": move.whoutid,
            "whinid": move.whinid,
            "whout_name": whout_name,
            "whin_name": whin_name,
            # "orderamount": float(move.orderamount) if move.orderamount else 0.0,
            # "whamount": float(move.whamount) if move.whamount else 0.0,
            # "yjamount": float(move.yjamount) if move.yjamount else 0.0,
            # "wjamount": float(move.wjamount) if move.wjamount else 0.0,
            "statu": move.statu,
            "shtime": shtime_str,
            "remark": move.remark,
            "create_by": move.create_by,
            "create_time": create_time_str,
            "update_by": move.update_by,
            "update_time": update_time_str
        }
        moves_with_details.append(move_dict)

    # 使用PageResult创建分页结果
    page_result = PageResult.create(rows=moves_with_details, count=total_count)

    return ApiResponse.ok(
        data=page_result
    )


@move_router.get('/list-all', summary="查询所有调拨订单（无分页）")
async def get_all_moves(
        start_date: Optional[str] = Query(None, description="开始日期，格式: YYYY-MM-DD"),
        end_date: Optional[str] = Query(None, description="结束日期，格式: YYYY-MM-DD"),
        whoutid: Optional[int] = Query(None, description="调出仓库ID"),
        whinid: Optional[int] = Query(None, description="调入仓库ID"),
        jwt: dict = Depends(my_oauth2_scheme)
) -> ApiResponse[List[dict]]:
    """
    查询所有调拨订单接口（无分页）
    
    参数:
    - start_date: 开始日期，格式: YYYY-MM-DD，可选
    - end_date: 结束日期，格式: YYYY-MM-DD，可选
    - whoutid: 调出仓库ID，可选
    - whinid: 调入仓库ID，可选
    """
    try:
        # 从JWT token中获取当前用户ID
        user_id = jwt["id"]

        # 构建查询条件
        query_filters = {
            "owner": user_id,
            "del_flag__not": "2"
        }

        # 处理仓库过滤
        if whoutid is not None:
            query_filters["whoutid"] = whoutid

        if whinid is not None:
            query_filters["whinid"] = whinid

        # 处理日期范围过滤
        if start_date:
            try:
                start_dt = datetime.strptime(start_date, "%Y-%m-%d")
                query_filters["create_time__gte"] = start_dt
            except ValueError:
                return ApiResponse.error(400, "开始日期格式错误，请使用YYYY-MM-DD格式")

        if end_date:
            try:
                end_dt = datetime.strptime(end_date, "%Y-%m-%d")
                # 结束日期需要包含当天的23:59:59
                query_filters["create_time__lte"] = datetime.combine(end_dt, datetime.max.time())
            except ValueError:
                return ApiResponse.error(400, "结束日期格式错误，请使用YYYY-MM-DD格式")

        # 查询所有调拨订单（无分页）
        moves = await MoveOrder.filter(**query_filters).order_by("-create_time").all()

        # 获取仓库名称信息并构建结果列表
        moves_with_details = []
        for move in moves:
            # 获取经办人名称
            owner_name = None
            if move.owner:
                owner_user = await User.filter(user_id=move.owner, del_flag__not="2").first()
                if owner_user:
                    owner_name = owner_user.nick_name

            # 获取调出仓库名称
            whout = await Warehouse.get_or_none(whid=move.whoutid, del_flag__not="2")
            whout_name = whout.whname if whout else "未知仓库"

            # 获取调入仓库名称
            whin = await Warehouse.get_or_none(whid=move.whinid, del_flag__not="2")
            whin_name = whin.whname if whin else "未知仓库"

            # 格式化日期字段
            shtime_str = move.shtime.strftime("%Y-%m-%d %H:%M:%S") if move.shtime else None
            create_time_str = move.create_time.strftime("%Y-%m-%d %H:%M:%S") if move.create_time else None
            update_time_str = move.update_time.strftime("%Y-%m-%d %H:%M:%S") if move.update_time else None

            # 构建结果字典
            move_dict = {
                "moveid": move.moveid,
                "owner": move.owner,
                "ownername": owner_name,
                "whoutid": move.whoutid,
                "whinid": move.whinid,
                "whout_name": whout_name,
                "whin_name": whin_name,
                "statu": move.statu,
                "shtime": shtime_str,
                "remark": move.remark,
                "create_by": move.create_by,
                "create_time": create_time_str,
                "update_by": move.update_by,
                "update_time": update_time_str
            }
            moves_with_details.append(move_dict)

        return ApiResponse.ok(
            data=moves_with_details,
            msg="查询成功"
        )

    except Exception as e:
        return ApiResponse.error(500, f"查询调拨订单失败: {str(e)}")


@move_router.get('/detail/{moveid}', summary="查询调拨订单详情")
async def get_move_detail(moveid: str) -> ApiResponse[dict]:
    """
    根据调拨单号查询订单详情接口
    
    参数:
    - moveid: 调拨单号
    """
    # 查询主订单信息
    move_order = await MoveOrder.filter(moveid=moveid, del_flag__not="2").first()
    if not move_order:
        return ApiResponse.error(404, "调拨订单不存在")

    # 查询订单商品项
    move_items = await MoveItem.filter(
        moveid=moveid,
        del_flag__not="2"
    ).order_by("orderid").all()

    # 获取仓库名称
    whout = await Warehouse.get_or_none(whid=move_order.whoutid, del_flag__not="2")
    whout_name = whout.whname if whout else "未知仓库"

    whin = await Warehouse.get_or_none(whid=move_order.whinid, del_flag__not="2")
    whin_name = whin.whname if whin else "未知仓库"

    # 格式化主订单日期字段
    shtime_str = move_order.shtime.strftime("%Y-%m-%d %H:%M:%S") if move_order.shtime else None
    create_time_str = move_order.create_time.strftime("%Y-%m-%d %H:%M:%S") if move_order.create_time else None
    update_time_str = move_order.update_time.strftime("%Y-%m-%d %H:%M:%S") if move_order.update_time else None

    # 构建商品项详情（包含商品信息）
    items_with_product_info = []
    for item in move_items:
        # 获取商品信息（包括formulatext）
        product_info = None
        if item.pid:
            product = await Product.filter(pid=item.pid, del_flag__not="2").first()
            if product:
                product_info = {
                    "formulatext": product.formulatext,
                    "pname": product.pname,
                    "brand": product.brand,
                    "smallunit": product.smallunit,
                    "bigunit": product.bigunit
                }

        # 格式化商品项日期字段
        item_create_time_str = item.create_time.strftime("%Y-%m-%d %H:%M:%S") if item.create_time else None
        item_update_time_str = item.update_time.strftime("%Y-%m-%d %H:%M:%S") if item.update_time else None

        items_with_product_info.append({
            "itemid": item.itemid,
            "orderid": item.orderid,
            "pid": item.pid,
            "pname": item.pname,
            "unit": item.unit,
            "unitprice": float(item.unitprice) if item.unitprice else 0.0,
            "number": float(item.number) if item.number else 0.0,
            # "orderamount": float(item.orderamount) if item.orderamount else 0.0,
            # "whnumber": float(item.whnumber) if item.whnumber else 0.0,
            # "whamount": float(item.whamount) if item.whamount else 0.0,
            "whid": item.whid,
            "whname": item.whname,
            "remark": item.remark,
            "create_time": item_create_time_str,
            "create_by": item.create_by,
            "update_time": item_update_time_str,
            "update_by": item.update_by,
            "product_info": product_info
        })

    return ApiResponse.ok(data={
        "moveid": move_order.moveid,
        "owner": move_order.owner,
        "whoutid": move_order.whoutid,
        "whinid": move_order.whinid,
        "whout_name": whout_name,
        "whin_name": whin_name,
        "orderamount": float(move_order.orderamount) if move_order.orderamount else 0.0,
        # "whamount": float(move_order.whamount) if move_order.whamount else 0.0,
        # "yjamount": float(move_order.yjamount) if move_order.yjamount else 0.0,
        # "wjamount": float(move_order.wjamount) if move_order.wjamount else 0.0,
        "statu": move_order.statu,
        "shtime": shtime_str,
        "remark": move_order.remark,
        "create_by": move_order.create_by,
        "create_time": create_time_str,
        "update_by": move_order.update_by,
        "update_time": update_time_str,
        "list": items_with_product_info
    })
